<?php
/**
 *
 * @author Tongle Xu <xutongle@gmail.com> 2013-11-19
 * @copyright Copyright (c) 2003-2103 tintsoft.com
 * @license http://www.tintsoft.com
 * @version $Id$
 */
namespace Leaps\Exception;
use ErrorException;
class Handler
{
    /**
     * 简单的异常显示器
     *
     * @var \Leaps\Exception\ExceptionDisplayerInterface
     */
    protected $plainDisplayer;

    /**
     * 支持Debug的异常显示器
     *
     * @var \Leaps\Exception\ExceptionDisplayerInterface
     */
    protected $debugDisplayer;

    /**
     * 是否开启Debug模式
     *
     * @var bool
     */
    protected $debug;

    /**
     * Create a new error handler instance.
     *
     *
     * @param \Leaps\Exception\ExceptionDisplayerInterface $plainDisplayer
     * @param \Leaps\Exception\ExceptionDisplayerInterface $debugDisplayer
     * @return void
     */
    public function __construct(ExceptionDisplayerInterface $plainDisplayer, ExceptionDisplayerInterface $debugDisplayer, $debug = true)
    {
        $this->debug = $debug;
        $this->plainDisplayer = $plainDisplayer;
        $this->debugDisplayer = $debugDisplayer;
    }

    /**
     * 异常/错误处理程序注册到应用程序。
     *
     * @param string $environment
     * @return void
     */
    public function register($environment)
    {
        $this->registerErrorHandler ();
        $this->registerExceptionHandler ();
        if ( $environment != 'testing' ) $this->registerShutdownHandler ();
    }

    /**
     * 注册PHP错误处理
     *
     * @return void
     */
    protected function registerErrorHandler()
    {
        set_error_handler ( array (
                $this,
                'handleError'
        ) );
    }

    /**
     * 注册PHP异常处理
     *
     * @return void
     */
    protected function registerExceptionHandler()
    {
        set_exception_handler ( array (
                $this,
                'handleException'
        ) );
    }

    /**
     * 注册PHP停止处理
     *
     * @return void
     */
    protected function registerShutdownHandler()
    {
        register_shutdown_function ( array (
                $this,
                'handleShutdown'
        ) );
    }

    /**
     * PHP错误处理
     *
     * @param int $level
     * @param string $message
     * @param string $file
     * @param int $line
     * @param array $context
     */
    public function handleError($level, $message, $file, $line, $context)
    {
        if ( error_reporting () & $level ) {
            $e = new ErrorException ( $message, $level, 0, $file, $line );
            $this->handleException ( $e );
        }
    }

    /**
     * PHP停止监听
     *
     * @return void
     */
    public function handleShutdown()
    {
        $error = error_get_last ();
        if ( ! is_null ( $error ) ) {
            extract ( $error );
            if ( ! $this->isFatal ( $type ) ) return;
            $this->handleException ( new ErrorException ( $message, $type, 0, $file, $line ) );
        }
    }

    /**
     * 是否是致命错误
     *
     * @param int $type
     * @return bool
     */
    protected function isFatal($type)
    {
        return in_array ( $type, array (
                E_ERROR,
                E_CORE_ERROR,
                E_COMPILE_ERROR,
                E_PARSE
        ) );
    }

    /**
     * PHP异常处理
     *
     * @param \Exception $exception
     * @return void
     */
    public function handleException($exception)
    {
        $this->displayException ( $exception );
        $this->bail ();
    }

    /**
     * 显示异常给用户
     *
     * @param \Exception $exception
     * @return void
     */
    protected function displayException($exception)
    {
        $displayer = $this->debug ? $this->debugDisplayer : $this->plainDisplayer;
        $displayer->display ( $exception );
    }

    /**
     * 停止应用程序
     *
     * @return void
     */
    protected function bail()
    {
        exit ( 1 );
    }

    /**
     * 设置Debug等级
     *
     * @param bool $debug
     * @return void
     */
    public function setDebug($debug)
    {
        $this->debug = $debug;
    }
}